<?php
namespace Mlsmt\Cabinet;
use think\Db;
use think\Cache;
use think\Request;

//用于接收相关数据，
class Send
{
    var $waittime = 40000;  //循环间隔（单位微秒）

    var $donu = 250;  //循环次数

    var $socketservice = 'tcp://139.199.194.87:8282';  //发送命令地址

    var $headerkey = 'xinnar88833123';   //头部加密信息

    var $cabinet;  //机柜缓存

    var $Online;  //机柜是否在线

    var $cabinet_id;  //机柜ID

    function __construct($cabinet_id){
        $this ->cabinet_id = $cabinet_id;
        $this ->socketservice = config('tcpintraneturl');
        $this ->headerkey = config('headerkey');
        $cabinet = Cache::store('redis')->get($cabinet_id);
        $this ->cabinet = $cabinet;
        if($cabinet){
            $this->Online = true;
            /*$time = time();
            $registerduration = $time-$cabinet['registertime'];
            if($registerduration <= 500){
                $this->Online = true;
            }else{
                $heartbeatduration = $time-$cabinet['heartbeattime'];
                if($registerduration >= 5000){ //判断心跳是否超时
                    //删除相关在线信息
                    Cache::store('redis')->rm($cabinet_id);
                    isset($cabinet['client_id'])?Cache::store('redis')->rm($cabinet['client_id']):'';
                    $this->Online = false;
                }else{

                    $this->Online = true;
                }
            }
            */
        }else{
            $this->Online = false;
        }
    }

    //判断是否在线
    public function isOnline(){
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }else{
            $info['types'] = 1;
            $info['info'] = '机柜连接正常';
            return $info;
        }
    }

    //库存数量
    public function StockNum()
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }
        //获取机柜信息
        $cabinet = $this ->cabinet;

        if(isset($cabinet['stocknum'])){ //判断是否有库存信息

            $info['types'] = 1;
            $info['info'] = $cabinet['stocknum'];
            return $info;

        }else{

            $cabinet['stocknum'] = null;
            $cabinet['stockhex'] = null;
            Cache::store('redis')->set($cabinet_id,$cabinet);

            //发送查询库存相关的信息
            $str = "110,".$cabinet_id;

            $this ->socket($str);
            $status =0;
            while ($status<$this->donu) {
                usleep($this->waittime);
                $cabinet = Cache::store('redis')->get($cabinet_id);
                if($cabinet['stocknum']){

                    $info['types'] = 1;
                    $info['hex'] = $cabinet['stockhex'];
                    $info['info'] = $cabinet['stocknum'];
                    return $info;
                }else{
                    $status++;
                }
            }

        }

        $info['types'] = 0;
        $info['info'] ='连接机柜失败！';
        return $info;
    }
    //库存明细
    public function StockDetail()
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }
        //获取机柜信息
        $cabinet = $this ->cabinet;
        $cabinet['detail'] = null;
        $cabinet['detailhex'] = null;
        $cabinet['detailstatus'] = 0;
        Cache::store('redis')->set($cabinet_id,$cabinet);

        //发送查询库存相关的信息
        $str = "111,".$cabinet_id;

        $this ->socket($str);
        $status =0;
        while ($status<$this->donu) {
            usleep($this->waittime);
            $cabinet = Cache::store('redis')->get($cabinet_id);

            if($cabinet['detail']||$cabinet['detailstatus']==1){

                $info['types'] = 1;
                $info['hex'] = $cabinet['detailhex'];
                $info['info'] = $cabinet['detail'];
                $info['powernu'] = $cabinet['powernu'];
                return $info;
            }else{
                $status++;
            }
        }
        $info['types'] = 0;
        $info['info'] ='连接机柜失败！from detail';
        return $info;



    }
    //查询可借充电宝数量
    public function PowerNu()
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }
        //获取机柜信息
        $cabinet = $this ->cabinet;

        if(isset($cabinet['powernu'])){
            $info['types'] = 1;
            $info['info'] = $cabinet['powernu'];
            return $info;
        }else{
            $detail = $this->StockDetail();
            if($detail['types']==1){
                $info['types'] = 1;
                $info['info'] = $detail['powernu'];
                return $info;
            }else{
                $info['types'] = 0;
                $info['info'] = $detail['info'];
                return $info;
            }
        }

    }
    //查询充电宝ID
    public function Batteryid($lockid)
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }
        //获取机柜信息
        $cabinet = $this ->cabinet;
        $cabinet['detail'][$lockid]['batteryid'] = null;
        $cabinet['detail'][$lockid]['batteryidhex'] = null;
        Cache::store('redis')->set($cabinet_id,$cabinet);

        //发送查询
        $str = "112,".$cabinet_id.",".$lockid;

        $this ->socket($str);
        $status =0;
        while ($status<$this->donu) {
            usleep($this->waittime);
            $cabinet = Cache::store('redis')->get($cabinet_id);
            if($cabinet['detail'][$lockid]['batteryid']){

                $info['types'] = 1;

                $info['hex'] = $cabinet['detail'][$lockid]['batteryidhex'];
                $info['info'] = $cabinet['detail'][$lockid]['batteryid'];
                return $info;
            }else{
                $status++;
            }
        }
        $info['types'] = 0;
        $info['info'] ='连接机柜失败！';
        return $info;

    }
    //弹出指定位置充电宝
    public function EjectDevice($lockid)
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }
        //获取机柜信息
        $cabinet = $this ->cabinet;
        $cabinet['detail'][$lockid]['borrowstatus'] = null;
        $cabinet['detail'][$lockid]['borrowhex'] = null;

        Cache::store('redis')->set($cabinet_id,$cabinet);

        //发送查询
        $str = "200,".$cabinet_id.",".$lockid;

        $this ->socket($str);
        $status =0;
        while ($status<$this->donu) {
            usleep($this->waittime);
            $cabinet = Cache::store('redis')->get($cabinet_id);
            if($cabinet['detail'][$lockid]['borrowstatus']==1){

                $batteryid = $cabinet['detail'][$lockid]['batteryid'];
                $hex = $cabinet['detail'][$lockid]['borrowhex'];
                unset($cabinet['detail'][$lockid]);
                Cache::store('redis')->set($cabinet_id,$cabinet);
                $info['types'] = 1;
                $info['hex'] = $hex;
                $info['info'] = $batteryid;
                return $info;
            }elseif($cabinet['detail'][$lockid]['borrowstatus']==2){
                $hex = $cabinet['detail'][$lockid]['borrowhex'];
                unset($cabinet['detail'][$lockid]);
                Cache::store('redis')->set($cabinet_id,$cabinet);
                $info['types'] = 2;
                $info['hex'] = $hex;
                return $info;

            }else{
                $status++;
            }
        }

        $info['types'] = 0;
        $info['info'] ='连接机柜失败！';
        return $info;

    }
    /**
     * 借充电宝
     * @param [type] $cabinet_id [description]
     * @param  如果租借成功则返回充电宝ID
     */
    public function BorrowDevice()
    {
        $cabinet_id = $this->cabinet_id;
        $detail = $this->StockDetail(); //获取充电宝明细

        if($detail['types']==1){

            //判断电量最多锁ID
            $detail = $detail['info'];
            if(!$detail){
                $info['types'] = 3;
                $info['info'] ='没有充电宝！';
                return $info;
            }
            $cabinet = Cache::store('redis')->get($cabinet_id);

            //判断有没有坏的锁
            if(isset($cabinet['buglock'])){
                $buglock = explode(",",$cabinet['buglock']);
            }else{
                $buglock = array();
            }
            $power = array();

            //去除buglock的lockid
            $flipBuglock = array_flip($buglock);
            $detailNoBug = array_diff_key($detail, $flipBuglock);
            foreach ($detailNoBug as $key => $value) {
                $power[$key] = $value['power'];
            }

            //如果机柜中电量最多的充电宝，电量低于3（80%），返回没电。
            if (count($power) > 0) {
                if(max($power)<3){
                    $info['types'] = 4;
                    $info['info'] ='机柜中充电宝电量不足！';
                    return $info;
                }
            }else{
                $info['types'] = 3;
                $info['info'] ='没有可用充电宝！';
                return $info;
            }

            $maxpower = array_count_values($power); //获取每个电量值的数量

            //如果电量最多的数量大于1，这则循环查出他们的使用次数
            if($maxpower[max($power)]>1){
                $usetimes = array();
                foreach ($power as $key => $value) {
                    if( $value==max($power)){
                        $batteryid = $detail[$key]['batteryid'];
                        $usetimes[$key] =  Db::name('leaseorder')
                            ->where('deviceid',$batteryid)
                            ->count();
                    }
                }
                //锁ID等于使用此处最少的
                $lockid = array_search(min($usetimes),$usetimes);
            }else{
                //如果电量最多的只有一个，则锁ID等于电量最多的
                $lockid = array_search(max($power),$power);

            }

            //删除租借状态信息
            $cabinet['status'][$lockid]['borrowstatus'] = null;
            $cabinet['status'][$lockid]['borrowhex'] = null;
            Cache::store('redis')->set($cabinet_id,$cabinet);

            //发送查询
            $str = "200,".$cabinet_id.",".$lockid;

            $this ->socket($str);
            $status =0;
            while ($status<$this->donu) {
                usleep($this->waittime);
                $cabinet = Cache::store('redis')->get($cabinet_id);
                if($cabinet['status'][$lockid]['borrowstatus']==1){

                    $batteryid = $cabinet['status'][$lockid]['batteryid'];
                    $hex = $cabinet['status'][$lockid]['borrowhex'];

                    unset($cabinet['status'][$lockid]);
                    Cache::store('redis')->set($cabinet_id,$cabinet);
                    $info['types'] = 1;
                    $info['info'] = $batteryid;
                    $info['hex'] = $hex;
                    return $info;
                }elseif($cabinet['status'][$lockid]['borrowstatus']==2){
                    $hex = '';
                    unset($cabinet['status'][$lockid]);
                    Cache::store('redis')->set($cabinet_id,$cabinet);
                    $info['types'] = 2;
                    $info['info'] = '';
                    $info['hex'] = $hex;
                    return $info;

                }else{
                    $status++;
                }
            }

        }

        $info['types'] = 0;
        $info['info'] ='连接机柜失败！';
        return $info;

    }


    //查询版本
    public function Version()
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }
        //获取机柜信息
        $cabinet = $this ->cabinet;
        $cabinet['version'] = null;
        $cabinet['versionhex'] = null;
        Cache::store('redis')->set($cabinet_id,$cabinet);

        //发送查询
        $str = "114,".$cabinet_id;

        $this ->socket($str);
        $status =0;
        while ($status<$this->donu) {
            usleep($this->waittime);
            $cabinet = Cache::store('redis')->get($cabinet_id);
            if($cabinet['version']){

                $info['types'] = 1;
                $info['hex'] = $cabinet['versionhex'];
                $info['info'] = $cabinet['version'];
                return $info;
            }else{
                $status++;
            }
        }
        $info['types'] = 0;
        $info['info'] ='连接机柜失败！';
        return $info;

    }



    //查询配置文件
    public function GetConfigure()
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }
        //获取机柜信息
        $cabinet = $this ->cabinet;
        $cabinet['servicer'] = false;
        Cache::store('redis')->set($cabinet_id,$cabinet);

        //发送查询
        $str = "115,".$cabinet_id;

        $this ->socket($str);
        $status =0;
        while ($status<$this->donu) {
            usleep($this->waittime);
            $cabinet = Cache::store('redis')->get($cabinet_id);
            if($cabinet['servicer']){

                $info['types'] = 1;
                $info['hex'] = $cabinet['configurehex'];
                $info['info'] = array(
                    'servicer' => $cabinet['servicer'],
                    'port' => $cabinet['port'],
                    'heartbeat' => $cabinet['heartbeat'],
                );
                return $info;
            }else{
                $status++;
            }
        }
        $info['types'] = 0;
        $info['info'] ='连接机柜失败！';
        return $info;

    }

    /**
     * 更新配置文件
     * @param [str] $cabinet_id [机柜ID]
     * @param [str] $addr       [注册地址]
     * @param [str] $port       [端口]
     * @param [str] $heartbeat  [心跳间隔]
     */
    public function UpdateStatus($addr,$port,$heartbeat)
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }
        //获取机柜信息
        $cabinet = $this ->cabinet;
        $cabinet['updatestatus'] = null;
        Cache::store('redis')->set($cabinet_id,$cabinet);

        //发送查询
        $str = "202,".$cabinet_id.",".$addr.",".$port.",".$heartbeat;

        $this ->socket($str);
        $status =0;
        while ($status<$this->donu) {
            usleep($this->waittime);
            $cabinet = Cache::store('redis')->get($cabinet_id);
            if($cabinet['updatestatus']==1){

                $info['types'] = 1;
                $info['hex'] = $cabinet['updatehex'];
                $info['info'] = $cabinet['updatestatus'];
                return $info;
            }elseif($cabinet['updatestatus']==2){
                $info['hex'] = $cabinet['updatehex'];
                $info['types'] = 2;
                return $info;
            }else{
                $status++;
            }
        }
        $info['types'] = 0;
        $info['info'] ='连接机柜失败！';
        return $info;

    }

    /**
     * 远程升级
     * @param [type] $cabinet_id [机柜ID]
     * @param [type] $addr       [FTP服务器地址]
     * @param [type] $port       [端口]
     * @param [type] $filename   [文件名]
     * @param [type] $username   [用户名]
     * @param [type] $password   [密码]
     */
    public function RemoteUpdate($addr,$port,$filename,$username,$password)
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }
        //获取机柜信息
        $cabinet = $this ->cabinet;
        //发送查询
        $str = "204,".$cabinet_id.",".$addr.",".$port.",".$filename.",".$username.",".$password;

        $this ->socket($str);
        $status =0;
        while ($status<$this->donu) {
            usleep($this->waittime);
            $cabinet = Cache::store('redis')->get($cabinet_id);
            if(isset($cabinet['otatatus'])){
                $info['types'] = $cabinet['otatatus'];
                $info['hex'] = $cabinet['otahexs'];
                return $info;
                /*if($cabinet['otatatus']==1){
                }else{
                }*/
            }
            $status++;
        }
        $info['types'] = 0;
        return $info;

    }

    //重启
    public function Restart()
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }
        //获取机柜信息
        $cabinet = $this ->cabinet;
        $cabinet['restartstatus'] = null;
        Cache::store('redis')->set($cabinet_id,$cabinet);

        //发送查询
        $str = "203,".$cabinet_id;
        $this ->socket($str);

        $status =0;
        while ($status<$this->donu) {
            usleep($this->waittime);
            $cabinet = Cache::store('redis')->get($cabinet_id);
            if($cabinet['restartstatus']==1){

                $info['types'] = 1;
                $info['hex'] = $cabinet['restarthex'];
                $info['info'] = $cabinet['restartstatus'];
                return $info;
            }elseif($cabinet['restartstatus']==2){
                $info['types'] = 2;
                $info['hex'] = $cabinet['restarthex'];
                return $info;
            }else{
                $status++;
            }
        }

        $info['types'] = 0;
        $info['info'] ='连接机柜失败！';
        return $info;
    }

    //打开指定锁位的电子锁
    public function OpenALock($lockid)
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }

        //发送打开指定锁位的电子锁的信息
        $str = "250,".$cabinet_id.",".$lockid;

        $this ->socket($str);
        $status =0;
        while ($status<$this->donu) {
            usleep($this->waittime);
            $cabinet = Cache::store('redis')->get($cabinet_id);
            if($cabinet['status'][$lockid]['borrowstatus']==1){

                $batteryid = $cabinet['status'][$lockid]['batteryid'];
                $hex = $cabinet['status'][$lockid]['borrowhex'];

                unset($cabinet['status'][$lockid]);
                Cache::store('redis')->set($cabinet_id,$cabinet);
                $info['types'] = 1;
                $info['info'] = $batteryid;
                $info['hex'] = $hex;
                return $info;
            }else{
                $status++;
            }
        }

        $info['types'] = 0;
        $info['info'] ='连接机柜失败！';
        return $info;

    }

    //打开所有锁位的电子锁
    public function OpenAllLock()
    {
        $cabinet_id = $this->cabinet_id;
        if(!$this->Online){
            $info['types'] = 0;
            $info['info'] = '机柜不在线';
            return $info;
        }
        //初始化
        $devicenum = Db::name('charecabinet')->where(['cabinet_id' => $cabinet_id, 'is_delete' => 1])->field('cabinet_id, devicenum')->find();
        $devicenum = (int)$devicenum['devicenum'];
        $cabinet = $this->cabinet;
        $cabinet['status'][$devicenum]['borrowstatus'] = '';
        Cache::store('redis')->set($cabinet_id,$cabinet);

        $donu = 2*1000000*$devicenum/($this->waittime) + 50; // 2 -> 每个充电宝弹出的命令间隔2秒，1000000 -> 单位换算，50->多出50次使循环获得数据
        //发送查询
        $str = "251,".$cabinet_id;
        $this ->socket($str);
        $status =0;
        while ($status<$donu) {
            usleep($this->waittime);
            $cabinet = Cache::store('redis')->get($cabinet_id);
            if($cabinet['status'][$devicenum]['borrowstatus']==1){

                $batteryid = $cabinet['status'][$devicenum]['batteryid'];
                $hex = $cabinet['status'][$devicenum]['borrowhex'];

                unset($cabinet['status']);
                Cache::store('redis')->set($cabinet_id,$cabinet);
                $info['types'] = 1;
                $info['info'] = $batteryid;
                $info['hex'] = $hex;
                return $info;
            }else{
                $status++;
            }
        }
        $info['types'] = 0;
        $info['info'] ='连接机柜失败！';
        return $info;
    }

    public function socket($str){
        $client = stream_socket_client($this->socketservice);
        if(!$client)exit("can not connect");
        // 模拟超级用户，以文本协议发送数据，注意Text文本协议末尾有换行符（发送的数据中最好有能识别超级用户的字段），这样在Event.php中的onMessage方法中便能收到这个数据，然后做相应的处理即可
        // 已删除换行符 by Charles 2018/1/21
        $service = 'service';
        $time = time();
        $key = md5($this->headerkey.$time);
        $data = $service.','.$key.','.$time.','.$str;
        fwrite($client, $data);

    }


}

